from django.conf import settings
from rest_framework import viewsets, mixins, exceptions
from rest_framework.decorators import action
from rest_framework.parsers import MultiPartParser, JSONParser

from connection.models import Connection
from connection.serializers import ConnectionSerializer, ConnectionSimpleSerializer, CertificateSerializer
from connection.filters import ConnectionFilter
from libs.decorators import required_data_fields, permission_required, required_query_parameters
from libs.enums import Permission, PartnerType, ConnectionState, LogModule
from libs.simple_responses import api_success, api_created_success
from connection.services import connection_service
from task.services import schedule_service
from log.services import log_service


class ConnectionViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin):
    queryset = Connection.objects.all()
    serializer_class = ConnectionSerializer
    filterset_class = ConnectionFilter
    ordering_fields = ('id',)
    parser_classes = [JSONParser, MultiPartParser]

    def get_serializer_class(self):
        if self.action == 'simples':
            return ConnectionSimpleSerializer
        return super().get_serializer_class()

    def get_permissions(self):
        if self.action == 'import_certificate':
            return []
        return super().get_permissions()

    def get_log_module(self, type):
        if type == PartnerType.APP.value:
            return LogModule.APP_CONNECTION.value
        else:
            return LogModule.ORG_CONNECTION.value

    @permission_required([Permission.CONNECTION_MANAGE.value])
    @required_data_fields(['type'])
    def create(self, request, *args, **kwargs):
        type = request.data.get('type')
        partner = None
        if type == PartnerType.ORG.value:
            partner_name = request.data.get('partner_name')
            if not partner_name:
                raise exceptions.ValidationError({'error': 'partner_name不可为空'})
            partner = connection_service.get_or_create_org_partner(partner_name)
        elif type == PartnerType.APP.value:
            app_server = request.data.get('app_server')
            if not app_server:
                raise exceptions.ValidationError({'error': 'app_server不可为空'})
            partner = connection_service.create_app_parnter(app_server)
        else:
            raise exceptions.ValidationError({'error': 'type字段值有误'})
        connection = connection_service.create_connection(
            partner=partner,
            state=ConnectionState.ONGOING.value,
            start_time=request.data.get('start_time'),
            end_time=request.data.get('end_time')
        )
        if type == PartnerType.ORG.value:
            schedule_service.connection_created(connection)

        log_service.build_create_log(self.request.user, connection,
                                     module=self.get_log_module(type), content=f'创建了互联，合作方：{partner.name}')
        data = ConnectionSerializer(connection).data
        return api_created_success(data=data)

    @permission_required([Permission.CONNECTION_MANAGE.value])
    def update(self, request, *args, **kwargs):
        return super().update(request, *args, **kwargs)

    @permission_required([Permission.CONNECTION_MANAGE.value])
    def partial_update(self, request, *args, **kwargs):
        return super().partial_update(request, *args, **kwargs)

    @action(methods=['get'], detail=False, url_path='simples')
    def simples(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)

    @action(methods=['get'], detail=False, url_path='certificates/server')
    def get_certificate_server(self, request, *args, **kwargs):
        data = {
            'server': settings.HOST,
        }
        return api_success(data=data)

    @permission_required([Permission.CONNECTION_MANAGE.value])
    @required_data_fields(['source_data', 'server'])
    @action(methods=['post'], detail=True, url_path='certificates/generate')
    def generate_certificate(self, request, *args, **kwargs):
        ''' 生成我方授权书
        '''
        instance = self.get_object()
        certificate = connection_service.generate_certificate(instance, request.data.get('source_data'), request.data.get('server'))
        partner = instance.partner
        log_service.build_update_log(self.request.user, instance,
                                     module=self.get_log_module(partner.type), content=f'生成了授权书，合作方：{partner.name}')
        data = CertificateSerializer(certificate).data
        return api_success(data=data)

    @permission_required([Permission.CONNECTION_MANAGE.value])
    @action(methods=['post'], detail=True, url_path='certificates/upload')
    def upload_certificate(self, request, *args, **kwargs):
        ''' 上传对方授权书
        '''
        instance = self.get_object()
        file_object = request.data['file']
        certificate = connection_service.upload_certificate(instance, file_object)
        partner = instance.partner
        log_service.build_update_log(self.request.user, instance,
                                     module=self.get_log_module(partner.type), content=f'上传了授权书，合作方：{partner.name}')
        data = CertificateSerializer(certificate).data
        return api_success(data=data)

    @permission_required([Permission.CONNECTION_MANAGE.value])
    @required_data_fields(['state'])
    @action(methods=['post'], detail=True, url_path='state')
    def change_state(self, request, *args, **kwargs):
        instance = self.get_object()
        instance.state = request.data.get('state')
        instance.save()
        partner = instance.partner
        state_enum = ConnectionState.get_enum(instance.state)
        log_service.build_update_log(self.request.user, instance, module=self.get_log_module(partner.type),
                                     content=f'变更了互联的状态[{state_enum.desc}]，合作方：{partner.name}')
        return api_success({})

    @required_data_fields(['certificate_id'])
    @action(methods=['post'], detail=False, url_path='certificates/validate')
    def validate_certificate(self, request, *args, **kwargs):
        validated = connection_service.validate_certificate(request.data.get('certificate_id'))
        data = {
            'validated': validated
        }
        return api_success(data=data)

    @required_query_parameters(['certificate_id'])
    @action(methods=['get'], detail=False, url_path='certificates/filings')
    def get_filings(self, request, *args, **kwargs):
        data = connection_service.get_filings(request.query_params.get('certificate_id'))
        return api_success(data=data)
